package com.cn.udpDemo;

import com.cn.udpDemo.message.Message;
import com.cn.udpDemo.message.MessageType;
import com.cn.udpDemo.message.MessageUtils;

import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.charset.Charset;
import java.util.*;

public class UDPServer extends Thread {
    public void run () {
        Selector selector = null ;
        DatagramChannel channel = null;
        int udpPort=5000;
        Map<String,InetSocketAddress> mapAddr = new HashMap<>();
        try {
            channel = DatagramChannel.open ();
            channel.configureBlocking(false);
            DatagramSocket socket = channel.socket();
            socket.bind(new InetSocketAddress(udpPort));
            System.out.println("server start!2");
            selector = Selector.open () ;
            channel.register ( selector, SelectionKey.OP_READ ) ;
        } catch ( Exception e ) {
            e.printStackTrace () ;
        }

        ByteBuffer byteBuffer = ByteBuffer.allocate (100) ;
        while (true){
            try {
                int eventsCount = selector.select() ;
                if ( eventsCount > 0 ) {
                    Set selectedKeys = selector.selectedKeys () ;
                    Iterator iterator = selectedKeys.iterator () ;
                    while ( iterator.hasNext ()) {
                        SelectionKey sk = ( SelectionKey ) iterator.next () ;
                        iterator.remove () ;
                        if ( sk.isReadable ()) {
                            //在这里datagramChannel与channel实际是同一个对象
                            DatagramChannel datagramChannel = ( DatagramChannel ) sk.channel () ;
                            byteBuffer.clear();
                            InetSocketAddress sa = (InetSocketAddress) datagramChannel.receive(byteBuffer);
                            Message message = MessageUtils.fromByteBuffer(byteBuffer);
//                            byteBuffer.flip();
                            byte []  bytes = null;
                            ByteBuffer buffer = null;
                            switch (message.getType()){
                                case MessageType.SERVERLIST:
                                    List<InetSocketAddress> adList= new ArrayList<>(mapAddr.values()) ;
                                    bytes =  MessageUtils.toByteArray(adList);
                                    break;
                                case MessageType.HEARTBEAT:
                                    bytes = new byte[]{MessageType.HEARTBEAT};
                                    if(!mapAddr.containsKey(sa.toString())){
                                        mapAddr.put(sa.toString(),sa);
                                    }
//                                    buffer.flip();
                                    Thread.sleep(1000);//延时
                                    break;
                            }
                            message.setSize(bytes.length);
                            message.setData(bytes);
                            buffer = MessageUtils.toByteBuffer(message);// Charset.defaultCharset ().encode(echo);
                            datagramChannel.send(buffer,sa);
                            // 测试：通过将收到的ByteBuffer首先通过缺省的编码解码成Char.sBuffer 再输出
//                            CharBuffer charBuffer = Charset.defaultCharset ().decode( byteBuffer ) ;
//                            System.out.println ( "receive message:" + charBuffer.toString()) ;
//                            String echo = "server reply!";
//                            ByteBuffer buffer = Charset.defaultCharset ().encode(echo);
//
//                            Thread.sleep(1000);//延时
//                            datagramChannel.send(buffer,sa);

                        }
                    }//while iterator
                }//if
            } catch ( Exception e ) {
                e.printStackTrace () ;
            }
        }//while

    }

    public static void main ( String [] args ) {
        new UDPServer().start() ;
    }
}
